package cn.imatu.framework.log.utils;

import cn.imatu.framework.log.LyLogProperties;
import cn.imatu.framework.log.common.LogCons;
import cn.imatu.framework.tool.core.CollectionUtils;
import cn.imatu.framework.tool.core.StringUtils;
import org.slf4j.MDC;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 日志工具
 *
 * @author shenguangyang
 */
public class LogUtils {
    public static Pattern pattern;

    public static void init(LyLogProperties logProperties) {
        if (CollectionUtils.isEmpty(logProperties.getFilterStackTracePackages())) {
            return;
        }
        StringBuilder regexp = new StringBuilder();
        for (String word : logProperties.getFilterStackTracePackages()) {
            regexp.append("(?=.*").append(word).append(")");
        }
        pattern = Pattern.compile(regexp.toString());
    }

    /**
     * 在日志文件中，打印异常堆栈
     *
     * @param e 抛出的异常
     * @return String
     */
    public static String formatStackTrace(Throwable e) {
        StringWriter errorsWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(errorsWriter));
        String loginId = StringUtils.defaultString(MDC.get(LogCons.LOGIN_ID), "");
        String traceId = StringUtils.defaultString(MDCTraceUtils.getTraceId(), "");
        String errorStackTrace = errorsWriter.toString();

        String lineFeed = !errorStackTrace.contains("\r\n") ? "\n" : "\r\n";
        String splitSymbol = StringUtils.isAllEmpty(loginId, traceId) ? "" : ",";
        String joinString = String.format(" [%s%s%s]%s", loginId, splitSymbol, traceId,  lineFeed);
        if (Objects.nonNull(pattern)) {
            String[] stackTraceArray = errorStackTrace.split(lineFeed);
            errorStackTrace = Arrays.stream(stackTraceArray)
                .filter(line -> line.trim().startsWith("Caused by:") || pattern.matcher(line).find())
                .collect(Collectors.joining(joinString));
            errorStackTrace = pattern.matcher(stackTraceArray[0]).find() ? errorStackTrace : stackTraceArray[0] + lineFeed + errorStackTrace;
        } else {
            errorStackTrace = errorStackTrace.replace(lineFeed, joinString);
        }
        return errorStackTrace;
    }
}
